home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / news / readers / slnr / part2 < prev    next >
Encoding:
Internet Message Format  |  1993-08-11  |  60.2 KB

  1. From pgoujard@infocom.co.uk Wed Aug 11 23:32:43 1993
  2. Path: uunet!cs.utexas.edu!math.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!agate!doc.ic.ac.uk!uknet!infocom.co.uk!pgoujard
  3. From: pgoujard@infocom.co.uk (Philippe Goujard)
  4. Newsgroups: alt.sources
  5. Subject: SLNR v1.2.c an offline newsreader 2/3
  6. Message-ID: <21529@infocom.co.uk>
  7. Date: 12 Aug 93 00:23:23 GMT
  8. Followup-To: alt.usenet.offline-reader
  9. Organization: INFOCOM Public Access Unix, (ModemLine) +44 [0] 734 340055
  10. Lines: 2340
  11. X-Newsreader: TIN [version 1.1 PL9]
  12. Xref: uunet alt.sources:9101
  13.  
  14.  
  15.  
  16. #!/bin/sh
  17. # this is slnr.sh.02 (part 2 of a multipart archive)
  18. # do not concatenate these parts, unpack them in order with /bin/sh
  19. # file slnr/slnp.fmt continued
  20. #
  21. if test ! -r _shar_seq_.tmp; then
  22.  echo 'Please unpack part 1 first!'
  23.  exit 1
  24. fi
  25. (read Scheck
  26.  if test "$Scheck" != 2; then
  27.  echo Please unpack part "$Scheck" next!
  28.  exit 1
  29.  else
  30.     exit 0
  31.  fi
  32. ) < _shar_seq_.tmp || exit 1
  33. if test ! -f _shar_wnt_.tmp; then
  34.     echo 'x - still skipping slnr/slnp.fmt'
  35. else
  36. echo 'x - continuing file slnr/slnp.fmt'
  37. sed 's/^X//' << 'SHAR_EOF' >> 'slnr/slnp.fmt' &&
  38. original articles, they should be converted into single spaces.  All fields
  39. must be present, but some may be empty.  The "bytes" field must not be empty,
  40. since it provides necessary information for packet readers.  Each field must
  41. conform to the Internet RFC documents RFC-822 or RFC-1036.
  42. X
  43. Optionally, a header line may end with one or more extra TAB-separated fields
  44. for other RFC-compliant header fields, together with the header field names.
  45. e.g. "Supersedes: <1234@foovax>".  These fields are not defined by this
  46. version of the specification, and are by arrangement between the generator
  47. and recipient only.
  48. X
  49. This format is compatible with the news overview database format of C-news.
  50. The only difference being the substitution of an offset for the article
  51. number used by C-news.  The C-news format was designed to assist threading
  52. newsreaders, so this packet format should provide similar assistance to
  53. compliant packet readers.
  54. X
  55. The 'C' format is similar to 'c', except that the "mesgid" and "refs" fields
  56. are dropped.  These fields can commonly be quite long and are mainly of use to
  57. packet readers which perform Message-ID based message threading.  Packet
  58. readers which perform subject threading (i.e. sort on the subject line and
  59. then on the date and/or arrival order) do not require such information.  The
  60. format of the header lines in this case is as follows:
  61. X
  62. offset<TAB>subject<TAB>author<TAB>date<TAB>bytes<TAB>lines
  63. X
  64. Further TAB-separated fields may be added in future versions of this
  65. specification.
  66. X
  67. The "author" field is slightly different to the 'c' format.  Instead of
  68. an RFC-822 format address, it is just the author's name, extracted from the
  69. "From:" line of the message.  Most RFC-822 and RFC-1036 "From:" lines have one
  70. of the following forms:
  71. X
  72. X                        address
  73. X                        address (name)
  74. X                        name <address>
  75. X
  76. Names may sometimes be surrounded by double-quote characters, have embedded
  77. "(...)" sequences, or contain "useless" information after a comma (",") or
  78. slash ("/").  The main requirement is that the generating software produce
  79. some kind of (more or less) meaningful string for the name of the author which
  80. can be displayed to the user by a packet reader.  See RFC-822 and RFC-1036
  81. for more information on the syntax of the "From:" line in messages.
  82. X
  83. The 'i' index format is purely binary, using 8 bytes for each message in the
  84. corresponding message file.  The first 4 bytes specify the offset into the
  85. message file of the message and the remaining 4 bytes specify the number of
  86. bytes in the message.  Each 4-byte quantity is stored in big-endian order
  87. (high byte first).  This format is supplied to provide a trade-off between
  88. transmission time and easy extraction of messages from a message file.
  89. X
  90. It is recommended that packet generators support at least the 'C' format, and
  91. that packet readers support at least 'c', 'C' and 'i'.  If a type is
  92. unrecognised by a packet reader, then it must "pull apart" the message file
  93. into separate messages itself, or flag the message area as unparsable by the
  94. packet reader.
  95. X
  96. X
  97. 2.5 ) REPLIES File
  98. ~~~~~~~~~~~~~~~~~~
  99. X
  100. One of the remaining requirements is a mechanism for a user to upload replies
  101. or new messages to a generating system for mailing or posting.  While it is
  102. possible to re-use the AREAS file for this purpose, keeping the download and
  103. upload sections separate will help prevent messages being fed back into a
  104. network erroneously.
  105. X
  106. The REPLIES file has a similar format to the AREAS file.  Each line has the
  107. following form:
  108. X
  109. prefix<TAB>reply kind<TAB>type[<TAB>message_no]
  110. X
  111. The "prefix" and "type" fields are as before.  The "reply kind" field indicates
  112.  
  113. the mechanism to use when transmitting the messages in the message file.  The
  114. following values are currently defined:
  115. X
  116. mail : Transmit an RFC-822 compliant personal mail message
  117. news : Transmit an RFC-1036 compliant USENET news posting
  118. X
  119. The message_no field is optional and indicates the number of messages in
  120. the prefix.MSG file.
  121. X
  122. On a Unix system, transmission of mail and news is usually performed with the
  123. "sendmail" and "inews" programs respectively.  Additional kinds may be
  124. specified in a future version of this specification for other message formats.
  125. Note: it is discouraged that the kinds "mail" and "news" be used for anything
  126. other than RFC-compliant messages.  In particular, FidoNet or QWK messages
  127. should use a different reply kind.  Messages of the same reply kind can be
  128. placed in the same message file, or in separate message files.
  129. X
  130. Further TAB-separated fields may be added to the lines in the REPLIES file
  131. in a future version of this specification.
  132. X
  133. It is recommended that a message file type of 'b' or 'B' be used for sending
  134. replies to minimise the chance of message corruption.  The recommended index
  135. file types for replies are 'i' and 'n'.  The index types 'c' and 'C' are
  136. discouraged because they do not provide useful information for reply purposes.
  137. X
  138. The format of the messages in the message files should follow the relevant
  139. RFC standards, with the following restriction: any "From:", "Sender:",
  140. "Control:", "Approved:" or other similar "dangerous" header lines should be
  141. ignored by the system transmitting the replies to prevent forgeries from
  142. occuring.  In particular, the "From:" header should be determined from the
  143. user's login name, or some other similar means, rather than from any data
  144. supplied in the user's message.
  145. X
  146. In most cases, mail messages will contain "To:", "Subject:", "Cc:", "Bcc:"
  147. and "Reply-To:" header lines, and news messages will contain "Newsgroups:",
  148. "Subject:", "Followup-To:", "Keywords:", "Summary:" and "Reply-To:" header
  149. lines.  Other optional headers (especially MIME content headers) may also
  150. be present.
  151. X
  152. The automatic addition of a signature by the transmitting system is
  153. discouraged.  Signatures should be added by the user's message composition
  154. software instead, if desired.
  155. X
  156. A method for allowing replies from more than one person to be stored in the
  157. same packet was considered, but was rejected for security reasons.
  158. X
  159. 2.6) List File
  160. X
  161. The LIST file may be used to send a list of available message areas to the
  162. receiving system.  Its format is similar to the AREAS file, with the prefix
  163. field deleted.  Each line has the following form:
  164. X
  165. area name<TAB>type[<TAB>description]
  166. X
  167. where "area name" is the name of the message area, "type" is a 2 letter
  168. message and index type code and "description" is an optional message area
  169. description.  Further optional fields may be added in a future version of
  170. this specification.
  171. X
  172. 3) Future enhancements
  173. ======================
  174. X
  175. The obvious enhancement that can be made is to support other message formats,
  176. especially FidoNet formats.  Currently the message area file code 'q' is
  177. reserved for QWK-format messages.  This will be defined in a future version
  178. of this specification if demand warrants.
  179. X
  180. Experimentation with other formats is encouraged, but please contact the
  181. author first to prevent double-ups from occurring. 
  182. X
  183. X
  184. X
  185. X
  186. X
  187. Appendix A : Convention used by getnews and SLNR
  188. ===========
  189. X     
  190. X     A.1. Getnews (version 1.6)
  191. X     ~~~~~~~~~~~~
  192. X     Getnews creates .MSG files named "001.MSG" "002.MSG" etc...
  193. X     Usually 001.MSG is the user mailbox.
  194. X     Getnews does not create index files (.IDX) and sets the index type
  195. X     field to "n" (for none). Getnews does not create the INFO or LIST file
  196. X     either.
  197. X     Getnews does however use the optional fields in the AREAS file to
  198. X     store the description of the newsgroup and the number of articles.
  199. X
  200. X
  201. X
  202. X     A.2 SLNR (version 1.7)
  203. X     ~~~~~~~~
  204. X     SLNR does not check for indexes nor INFO, COMMAND or LIST files. 
  205. X     SLNR creates reply files under the name Rxxx.MSG where "xxx" is the
  206. X     name of the area file to which it is replying. If the files have been
  207. X     created by getnews, SLNR will create reply files under the names
  208. X     "R001.MSG" "R002.MSG" etc... 
  209. X     Like getnews, SLNR does not create indexes and sets the index_type
  210. X     field to "n".
  211. SHAR_EOF
  212. echo 'File slnr/slnp.fmt is complete' &&
  213. chmod 0440 slnr/slnp.fmt ||
  214. echo 'restore of slnr/slnp.fmt failed'
  215. Wc_c="`wc -c < 'slnr/slnp.fmt'`"
  216. test 28248 -eq "$Wc_c" ||
  217.     echo 'slnr/slnp.fmt: original size 28248, current size' "$Wc_c"
  218. rm -f _shar_wnt_.tmp
  219. fi
  220. # ============= slnr/slnr.c ==============
  221. if test -f 'slnr/slnr.c' -a X"$1" != X"-c"; then
  222.     echo 'x - skipping slnr/slnr.c (File already exists)'
  223.     rm -f _shar_wnt_.tmp
  224. else
  225. > _shar_wnt_.tmp
  226. echo 'x - extracting slnr/slnr.c (Text)'
  227. sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnr.c' &&
  228. /*
  229. ** SLNR          : Simple Local News Reader
  230. ** Author        : P.Goujard
  231. ** Started       : 22/01/93
  232. ** Version       : 2.11
  233. ** Last modified : 11 Aug 1993
  234. */
  235. X
  236. #include <stdio.h>
  237. #include <string.h>
  238. #include <sys/types.h>
  239. #include <sys/stat.h>
  240. #include <ctype.h>  /* for toupper */
  241. #include <stdlib.h> /* For getenv */
  242. #include "colour.h"
  243. X
  244. #ifdef ATARI
  245. #include <mintbind.h>
  246. #include <vt52.h>
  247. #endif
  248. X
  249. #ifdef OS2
  250. #include <io.h>
  251. #include <conio.h>
  252. #endif
  253. X
  254. #ifndef ATARI
  255. #include <fcntl.h>        /* MS-DOS *does* need fcntl.h, but not termio.h    */
  256. #ifndef __MSDOS__
  257. #ifndef OS2
  258. #include <unistd.h>
  259. /*
  260. ** This is used for putting the terminal in raw mode
  261. ** Under dos we don't need that since getch() returns directly
  262. */
  263. #include <termio.h>
  264. #endif
  265. #endif
  266. #endif
  267. X
  268. #define NEWSLIST "AREAS"
  269. #define NEWSTXT ".MSG"
  270. #define MMDF_SEPARATOR ""
  271. #define MAIL_SEPARATOR "From "
  272. #define REWIND     1
  273. #define SET        1
  274. #define UNSET      0
  275. #define ASK        2
  276. X
  277. #define NO_HEADER   1L
  278. #define GET_SUBJECT 2L
  279. #define GET_ID      4L
  280. #define GET_FROM    8L
  281. #define GET_REPLYTO 16L
  282. X
  283. #define INITFILE "slnr.ini"
  284. X
  285. #ifdef __MSDOS__
  286. #  define PAGER "more <"
  287. #  define EDIT "q"
  288. #  define COMPRESS "pkzip"
  289. #  define MAXART 500 /* 1000        /* Originally 500    */
  290. #  define MAXGRP 100 /* 500        /* Originally 100    */
  291. #else
  292. #  ifdef ATARI
  293. X     char PAGER[64];
  294. #    define EDIT "???" /* To be defined by atari guru */
  295. #    define COMPRESS "stzip"  /* To be defined by atari guru */
  296. #    define MAXART 1000
  297. #    define MAXGRP 200
  298. #  else /* Unix */
  299. #    define PAGER "simplpg"
  300. #    define EDIT "simpled"
  301. #    define COMPRESS "zip"
  302. #    define MAXART 5000
  303. #    define MAXGRP 1000
  304. #   endif
  305. #endif
  306. X
  307. /*
  308. ** Global variables
  309. */
  310. static char pager_str[80],edit_str[80],compress_str[80],quote_str[80];
  311. static int use_ansi;
  312. int Lines=24;
  313. X
  314. struct header{
  315. X    char *subject;
  316. X    char *from;
  317. X    char *id;
  318. X    char *replyto;
  319. };
  320. X
  321. /*
  322. ** The idea of a color_string array is to allow several scr() call in
  323. ** one printf.
  324. ** If we don't do that printf only see the last scr() since they all
  325. ** have the same address.
  326. */
  327. char Color_string[MAX_CLR][12];
  328. int Color_no = 0;
  329. X
  330. X
  331. /*
  332. ** This is not very clean : those 2 arrays should be allocated
  333. ** only when needed instead of reserving memory which maybe won't
  334. ** be used.
  335. */
  336. struct arts {
  337. X    char from[20];
  338. X    unsigned long size;
  339. X    char subject[60];
  340. X    unsigned long rank;
  341. X    unsigned long ptr;              /* Pointer to start of article */
  342. }
  343. #ifdef __MSDOS2__    /* Create huge array if MS-DOS    */
  344. X    huge article[MAXART];
  345. #else
  346. X    article[MAXART];
  347. #endif
  348. X
  349. struct grps {
  350. X    char prefix[10]; /* The .MSG file containing the articles */
  351. X    char name[40];
  352. X    char desc[80];
  353. X    unsigned int art;   /* number of articles in that group */
  354. X    unsigned long start; /* number of 1st article in the article[] table */
  355. X    char msg_type;
  356. X    char idx_type;
  357. X    unsigned int reply; /* Number of replies for that group, default 0 */
  358. }
  359. #ifdef __MSDOS2__    /* Create huge array if MS-DOS    */
  360. X    huge group[MAXGRP];
  361. #else
  362. X    group[MAXGRP];
  363. #endif
  364. X
  365. unsigned int cur_grp=0, cur_art=0, old_cur_art=0, cur_line=0;
  366. int no=0;
  367. X
  368. #ifdef ATARI
  369. X
  370. static void cls (void);
  371. X
  372. int atari_res = 0;
  373. int atari_old_colour[16];
  374. X
  375. static void initialise_atari(void)
  376. {
  377. X    int   i;
  378. X    char *pager;
  379. X
  380. X    /*
  381. X     * Check the environment to see if a suitable pager is defined.
  382. X     * If so, make up the PAGER format string to use it. In all other
  383. X     * cases make up a generic call to "more".
  384. X     */
  385. X
  386. X    pager = (char*)getenv("PAGER");
  387. X
  388. X    if (pager==(char*)NULL) {
  389. X        sprintf(PAGER, "more ");
  390. X    } else {
  391. X        sprintf(PAGER, "%s ", pager);
  392. X    }
  393. X
  394. X    /*
  395. X     * Pick up screen resolution (used in function "scr").
  396. X     */
  397. X
  398. X    atari_res = Getrez();
  399. X    if (atari_res==0) {
  400. X        fprintf(stderr, "Cannot run in ST-low resolution\n");
  401. X        exit(1);
  402. X    };
  403. X
  404. X    /*
  405. X     * Record the original palette values for restore later
  406. X     */
  407. X
  408. X    for (i=0; i<16; i++) atari_old_colour[i] = Setcolor(i, -1);
  409. X
  410. X    /*
  411. X     * Set up the colour palette to match up colours with the
  412. X     * numbers used in the colour.h include file.
  413. X     */
  414. X
  415. X    (void) Setcolor(1, 0x000);        /* Black   */
  416. X    (void) Setcolor(2, 0x700);        /* Red     */
  417. X    (void) Setcolor(3, 0x070);        /* Green   */
  418. X    (void) Setcolor(4, 0x770);        /* Yellow  */
  419. X    (void) Setcolor(5, 0x007);        /* Blue    */
  420. X    (void) Setcolor(6, 0x707);        /* Magenta */
  421. X    (void) Setcolor(7, 0x077);        /* Cyan    */
  422. X    (void) Setcolor(8, 0x777);        /* White   */
  423. X
  424. X    /*
  425. X     * Now clear the screen
  426. X     */
  427. X
  428. X     printf("%s\n", scr(1,WHITE, BLACK));
  429. X     cls();
  430. }
  431. X
  432. static void closedown_atari(void)
  433. {
  434. X    int i;
  435. X
  436. X    /*
  437. X     * Restore the original colour palette
  438. X     */
  439. X     for (i=0; i<16; i++) (void) Setcolor(i, atari_old_colour[i]);
  440. }
  441. X
  442. #endif
  443. X
  444. /*
  445. ** Generates a string with ansi colors
  446. ** The unix version checks the environment variable TERM
  447. */
  448. #ifdef __STDC__
  449. char *scr(int attribute,int foreground, int background)
  450. #else
  451. char *scr(attribute,foreground, background)
  452. int attribute,foreground,background;
  453. #endif
  454. {
  455. X    char att_str[20],for_str[20],back_str[20];
  456. X    int n = Color_no;
  457. X
  458. X    if (!use_ansi)
  459. X    {
  460. X        sprintf (Color_string[0],""); /* NULL string */
  461. X        return(Color_string[0]);
  462. X    }
  463. X
  464. #ifdef ATARI
  465. X
  466. X    Color_string[n][0] = '\0';
  467. X
  468. X    if (atari_res==2 || atari_res==5)
  469. X        return(Color_string[n]);  /* Skip colour change on mono screens */
  470. X
  471. X    if (foreground!=NONE) {
  472. X        sprintf(for_str,  "%cb%c", '\033', 'a'+foreground);
  473. X        strcat(Color_string[n], for_str);
  474. X    };
  475. X
  476. X    if (background!=NONE) {
  477. X        sprintf(back_str, "%cc%c", '\033', 'a'+background);
  478. X        strcat(Color_string[n], back_str);
  479. X    };
  480. X
  481. X
  482. #else
  483. X
  484. #ifndef __MSDOS__
  485. X    if ( strstr((char *) getenv("TERM"),"ansi") == NULL)
  486. X    {
  487. X        Color_string[0][0] = '\0';
  488. X        return (Color_string[0]);
  489. X    }
  490. #endif
  491. X    att_str[0] = '\0';
  492. X    for_str[0] = '\0';
  493. X    back_str[0] = '\0';
  494. X    if (attribute != NONE)
  495. X    {
  496. X        sprintf (att_str,"%d",attribute);
  497. X        if (foreground != NONE || background != NONE)
  498. X            strcat(att_str,";");
  499. X    }
  500. X    if (foreground != NONE)
  501. X    {
  502. X        sprintf (for_str,"%d",30+foreground);
  503. X        if (background != NONE)
  504. X            strcat(for_str,";");
  505. X    }
  506. X    if (background != NONE)
  507. X        sprintf (back_str,"%d",40+background);
  508. X    sprintf (Color_string[n],"%s%s%s%sm",COL_HEAD,att_str,
  509. X        for_str,back_str);
  510. #endif
  511. X    Color_no++;
  512. X    Color_no = Color_no%MAX_CLR;
  513. X    return (Color_string[n]);
  514. }
  515. X
  516. void cls(void)
  517. {
  518. #ifndef __MSDOS__
  519. #ifdef ATARI
  520. X    printf(CLEAR_HOME); fflush(stdout);
  521. #else
  522. X    if ( strstr((char *) getenv("TERM"),"ansi") != NULL)
  523. X        printf("\033[0;37;40m\033[2J\033H\n"); 
  524. X    else 
  525. X        system("tput clear 2>/dev/null");     /* else use clear with terminfo */
  526. #endif
  527. #else
  528. X        printf("\033[0;37;40m\033[2J\033[H");
  529. X        fflush(stdout);
  530. #endif
  531. }
  532. X
  533. /* Remove unwanted characters */
  534. char *stripchars(line)
  535. char *line;
  536. {
  537. X    char newstr[255];
  538. X    char *str = line;
  539. X    int i = 0;
  540. X
  541. X    if (strlen(line) == 0)
  542. X        return (NULL);
  543. X
  544. X    while (*str)
  545. X    {
  546. X         if ((*str >= ' ') && (*str <= '~'))
  547. X            newstr[i++]=*str;
  548. X        str++;
  549. X    }
  550. X    newstr[i] = '\0';
  551. X    strcpy (line,newstr);
  552. X
  553. X    return(line);
  554. }
  555. X
  556. char *remove_cr(line)
  557. char *line;
  558. {
  559. X    int l;
  560. X    l = strlen(line);
  561. X    if( line[l-1] == '\n')
  562. X        line[l-1] = '\0';
  563. X    return(line);
  564. }
  565. X
  566. /* 
  567. ** Like fgets but with a prompt and check line length 
  568. */
  569. void fgetstr( prompt, line, default_value, size, fr)
  570. char *prompt,*line,*default_value;
  571. int size;
  572. FILE *fr;
  573. {
  574. X    int l=1,i;
  575. X    if (fr == stdin)
  576. X    {
  577. X        /* We only display the prompt if we are reading from stdin */
  578. X        printf ("%s%s%s ",scr(1,3,0),prompt,scr(1,1,0));
  579. X        if (default_value && *default_value)
  580. X        {
  581. X            if ((int)strlen(default_value) > size)
  582. X                default_value[size]='\0';
  583. X            printf("%s",default_value);
  584. X            l=strlen(default_value);
  585. X        }
  586. X        for (i = 0;i < size-l; i++)
  587. X            printf (".");
  588. X        printf ("\r%s%s%s ",scr(1,3,0),prompt,scr(8,7,0));
  589. X        fflush(stdout);
  590. X    }
  591. X    fflush(fr);
  592. X    if (fgets(line,size,fr) == NULL)
  593. X    {
  594. X        /* Return the default */
  595. X        strcpy(line,default_value);
  596. X        return;
  597. X    }
  598. X    line[size] = '\0';
  599. X    l = strlen(line);
  600. X    if (line[l-1] == '\n')
  601. X        line[l-1] = '\0';
  602. X    fflush (fr);
  603. X    stripchars(line);
  604. X    if (*line==0) /* Blank line */
  605. X        strcpy (line,default_value);
  606. }
  607. X
  608. /*
  609. X This is the core of the program, where we build the index table
  610. X For each newsgroup we fill an entry in  the group[] array
  611. X as well as for each article of a group.
  612. X This make moving between groups very quick.
  613. X However, reading an article can be slow : there is no index to point
  614. X directly to an article, we only know the rank of the article.
  615. X
  616. X However compared to the .ndx method used by QWK readers, this is not
  617. X dramatically slower. First of all the .dat files for QWK are bigger than
  618. X our MSG files : each article has to be adjusted to be on an exact
  619. X number of 128bytes block. And QWK .dat files contains header information
  620. X that are far too restrictive.
  621. */
  622. X
  623. void extract_article(ntext,size,separator,rewind_type)
  624. FILE *ntext;
  625. unsigned long size; /* Size of the article, if provided ignore the separator */
  626.  
  627. char *separator;
  628. int rewind_type; /* if set to REWIND, will unget the last line */
  629. {
  630. X    unsigned int l,end_of_article, headermode;
  631. X    unsigned long bytes_read, line_cnt, file_pos;
  632. X    char *pos,*p,temp[255],line[255];
  633. X
  634. X    if (size==0)
  635. X        l=strlen(separator);
  636. X    headermode=1;
  637. X    end_of_article=0;
  638. X    line_cnt=1;
  639. X    bytes_read=0;
  640. X
  641. X    while (!end_of_article)
  642. X    {
  643. X        file_pos = ftell(ntext);
  644. X        pos = fgets(line,255,ntext);
  645. X
  646. X        if (pos==NULL)
  647. X            end_of_article=1;
  648. X        else
  649. X        {
  650. X            /* Have we reached the end ? */
  651. X            bytes_read += strlen(line);
  652. X            if (size) /* For usenet message */
  653. X            {
  654. X                if (bytes_read>=size)
  655. X                    end_of_article=1;
  656. X            }
  657. X            else if (strncmp(line,separator,l)==0)
  658. X                end_of_article = 1;
  659. X
  660. X            if (!end_of_article)
  661. X            {
  662. X                if (headermode)
  663. X                {
  664. X                    if (line[0]=='\n')
  665. X                    {
  666. X                        headermode=0; /* End of Header, start of article body */
  667. X                        line_cnt=0;
  668. X                    }
  669. X                    line[strlen(line)-1]='\0';
  670. X                    if (strncmp(line,"From: ",6)==0)
  671. X                    {
  672. X                        /* Is there a name between () ? */
  673. X                        p=strchr(line,'(');
  674. X                        if (p)
  675. X                        {
  676. X                            strcpy (temp,p+1);
  677. X                            p=strrchr(temp,')');
  678. X
  679. X                            /* We need at least 4 chars in the name */
  680. X                            if (p < temp+4)
  681. X                                strcpy( temp, line+6);
  682. X                            else
  683. X                                *p='\0';
  684. X                        }
  685. X                        else /* Nope, just use the address as name */
  686. X                            strcpy(temp,line+6);
  687. X                        strncpy (article[cur_art].from,temp,16);
  688. X                        article[cur_art].from[16]='\0';
  689. X                    }
  690. X                    else if( strncmp(line,"Subject: ",9)==0 )
  691. X                    {
  692. X                        char *lpos = line+9;
  693. X                        while (( *lpos == ' ' ) || ( *lpos == '\t' ))
  694. X                            lpos++;
  695. X                        strncpy( article[cur_art].subject, lpos, 59);
  696. X                        article[cur_art].subject[50] = '\0';
  697. X                    }
  698. X                }
  699. X                else
  700. X                    line_cnt++;
  701. X            }
  702. X        }
  703. X    }
  704. X    article[cur_art].size=line_cnt;
  705. X    if (rewind_type == REWIND)
  706. X        fseek(ntext,file_pos,0);
  707. }
  708. X
  709. void index_all()
  710. {
  711. X    char gline[255],line[255],*p,area_name[80];
  712. X    int line_no=0,n;
  713. X    unsigned long size, file_pos;
  714. X    FILE *nlist,*ntext;
  715. X
  716. X    /* Open the files */
  717. X    if ((nlist=fopen(NEWSLIST,"r"))==NULL)
  718. X    {
  719. X        fprintf (stderr,"Unable to open <%s>\n",NEWSLIST);
  720. X        exit(1);
  721. X    }
  722. X
  723. X    /* For each newsgroup */
  724. X    while (fgets(gline,255,nlist)!=NULL)
  725. X    {
  726. X        line_no++;
  727. X        if (gline[0]!='#') /* Ignore commented out lines */
  728. X        {
  729. X            /* Ignore comments at end of line */
  730. X            if ((p=strrchr(gline,'#'))!=NULL)
  731. X                *p='\0';
  732. X            if (gline[strlen(gline)-1]=='\n')
  733. X                gline[strlen(gline)-1]='\0';
  734. X
  735. X            /*
  736. X            ** Get the prefix name and open the file
  737. X            */
  738. X            if ((p=strchr(gline,'\t'))==NULL)
  739. X            {
  740. X                fprintf (stderr,"Invalid entry in the AREAS file, line %d\n",line_no);
  741. X                exit(1);
  742. X            }
  743. X            *p='\0';
  744. X            sprintf(area_name,"%s%s",gline,NEWSTXT);
  745. X            if ((ntext=fopen(area_name,"r"))==NULL)
  746. X            {
  747. X                fprintf(stderr,"Unable to open area <%s>\n",area_name);
  748. X                exit(1);
  749. X            }
  750. X            strcpy(group[cur_grp].prefix,gline);
  751. X            group[cur_grp].start=cur_art;
  752. X            strcpy(gline,p+1);
  753. X
  754. X            /*
  755. X            ** Get the group name
  756. X            */
  757. X            if ((p=strchr(gline,'\t'))==NULL)
  758. X            {
  759. X                fprintf (stderr,"Invalid entry in the AREAS file, line %d\n",line_no);
  760. X                exit(1);
  761. X            }
  762. X            *p='\0';
  763. X            strcpy (group[cur_grp].name,gline);
  764. X            p++;
  765. X            strcpy (gline,p);
  766. X            p=gline;
  767. X
  768. X            /*
  769. X            ** Get the types
  770. X            */
  771. X            if (*p=='\0')
  772. X            {
  773. X                fprintf (stderr,"Invalid entry in the AREAS file, line %d\n",line_no);
  774. X                exit(1);
  775. X            }
  776. X            group[cur_grp].msg_type=*p;
  777. X            p++;
  778. X            if (*p=='\0')
  779. X            {
  780. X                fprintf (stderr,"Invalid entry in the AREAS file, line %d\n",line_no);
  781. X                exit(1);
  782. X            }
  783. X            group[cur_grp].idx_type=*p;
  784. X            p++;
  785. X            if (*p=='\0') /* No optional field */
  786. X                goto area_done;
  787. X            strcpy(gline,p+1);
  788. X
  789. X            /*
  790. X            ** Get the group description
  791. X            */
  792. X            if ((p=strchr(gline,'\t'))==NULL)
  793. X            {
  794. X                strcpy(group[cur_grp].desc,gline);
  795. X                goto area_done;
  796. X            }
  797. X            *p='\0';
  798. X            strcpy(group[cur_grp].desc,gline);
  799. X            strcpy(gline,p+1);
  800. X
  801. #ifdef NEVER /* This may be needed in the future */
  802. X            /*
  803. X            ** Get the number of articles
  804. X            */
  805. X            if ((p=strchr(gline,'\t'))==NULL)
  806. X            {
  807. X                group[cur_grp].art = atol(gline);
  808. X                goto area_done;
  809. X            }
  810. X            *p='\0';
  811. X            group[cur_grp].art = atol(gline);
  812. X            strcpy (gline,p+1);
  813. #endif
  814. X
  815. area_done:
  816. X            printf("\nReading %s ", group[cur_grp].name );
  817. X
  818. X            /*
  819. X            ** For each article
  820. X            */
  821. X            n=0;
  822. X            file_pos = ftell(ntext);
  823. X            while(fgets(line,255,ntext)!=NULL)
  824. X            {
  825. X                if ((n%10)==0)
  826. X                {
  827. X                    printf (".");
  828. X                    fflush(stdout);
  829. X                }
  830. X                switch(group[cur_grp].msg_type)
  831. X                {
  832. X                    case 'm': /* Mailbox format */
  833. X                        /*
  834. X                        ** Read the From line
  835. X                        */
  836. X                        if (strncmp(line,MAIL_SEPARATOR,5))
  837. X                        {
  838. X                            fprintf(stderr,"Line <%s> not in mail format\n",line);
  839. X                            exit(1);
  840. X                        }
  841. X                        article[cur_art].ptr = file_pos;
  842. X                        extract_article(ntext,0L,MAIL_SEPARATOR,REWIND);
  843. X                        break;
  844. X
  845. X                    case 'M': /* MMDF format */
  846. X                        /*
  847. X                        ** Read the Ctrl As line
  848. X                        */
  849. X                        if (strncmp(line,MMDF_SEPARATOR,4))
  850. X                        {
  851. X                            fprintf(stderr,"Line <%s> not in MMDF format\n",line);
  852. X                            exit(1);
  853. X                        }
  854. X                        article[cur_art].ptr = ftell(ntext);
  855. X                        extract_article(ntext,0L,MMDF_SEPARATOR,0);
  856. X                        break;
  857. X
  858. X                    case 'u': /* Usenet news format */
  859. X                        /*
  860. X                        ** Read the rnews line
  861. X                        */
  862. X                        if (strncmp(line,"#! rnews ",9))
  863. X                        {
  864. X                            fprintf(stderr,"Line <%s> not in rnews format\n",line);
  865. X                            exit(1);
  866. X                        }
  867. X                        size = atol(line+9);
  868. X                        article[cur_art].ptr = ftell(ntext);
  869. X                        if( size )
  870. X                            extract_article(ntext,size,"",0);
  871. X                        break;
  872. X
  873. X                    default:
  874. X                        fprintf(stderr,"Error: Message type <%c> not supported\n",
  875. X                            group[cur_grp].msg_type);
  876. X                        exit(1);
  877. X                }
  878. X                article[cur_art].rank=n;
  879. X                /*
  880. X                ** Here should be the code to malloc() a new article
  881. X                ** For the moment we just check that we are not going
  882. X                ** further than the boundary
  883. X                */
  884. X                if (cur_art>=MAXART)
  885. X                    return;
  886. X                cur_art++;
  887. X                n++;
  888. X                file_pos = ftell(ntext);
  889. X            }
  890. X            group[cur_grp].art=n;
  891. X            /*
  892. X            ** Here should be the code to malloc() a new group
  893. X            ** For the moment we just check that we are not going
  894. X            ** further than the boundary
  895. X            */
  896. X            fclose(ntext);
  897. X            if (cur_grp>=MAXGRP)
  898. X                return;
  899. X            cur_grp++;
  900. X        }
  901. X    }
  902. X    fclose (nlist);
  903. }
  904. X
  905. void disp_f(ptr)
  906. struct arts *ptr;
  907. {
  908. X    printf ("%s%3ld %s%-16s %s%4ld %s%-53s\n",
  909. X        (ptr->rank+1)==no ? scr(1,GREEN,0) : scr(1,YELLOW,0), ptr->rank+1,
  910. X        scr(1,MAGENTA,0),ptr->from,
  911. X        scr(1,YELLOW,0),ptr->size+1,
  912. X        scr(1,CYAN,0),ptr->subject);
  913. }
  914. X
  915. void show_header()
  916. {
  917. X    int n=group[cur_grp].art;
  918. X    char desc[80];
  919. X
  920. X    cls();
  921. X    sprintf( desc, "%s  <%s>", group[cur_grp].name, group[cur_grp].desc );
  922. X    desc[59] = '\0';
  923. X
  924. X    printf( "%sGroup %s%-60s %s%d %sarticle%c\n",
  925. X        scr( 1, GREEN, 0 ), scr( 1, CYAN, 0 ), desc, 
  926. X        scr(1,YELLOW,0),n,scr(1,GREEN,0),(n>1) ? 's' : ' ');
  927. X
  928. X    printf ("    %sFrom             Lines         Subject\n",scr(1,CYAN,0));
  929. X    printf ("%s==================================================================
  930. ==========\n",scr(1,GREEN,0));
  931. }
  932. X
  933. char ch_get(void)
  934. {
  935. #ifdef ATARI
  936. X    return((char)Cnecin());
  937. #else
  938. #ifdef __MSDOS__
  939. X    return (getch());
  940. #else
  941. #ifdef OS2
  942. X    return (getch());
  943. #else
  944. X    int file;
  945. X    char return_char;
  946. X    struct termio newterm, oldterm;
  947. X    file = open("/dev/tty", O_RDONLY);
  948. X    if (file == -1)
  949. X        return (0);
  950. X    ioctl(file,TCGETA,&oldterm);
  951. X    memcpy (&newterm,&oldterm,sizeof(struct termio));
  952. X    newterm.c_cc[4] = 1;
  953. X    newterm.c_cc[5] = 0;
  954. X    /* newterm.c_cflag = (B9600|CS8|CREAD); */
  955. X    newterm.c_lflag = 0;
  956. X    newterm.c_iflag = IGNBRK;
  957. X    newterm.c_oflag = 0;
  958. X    ioctl (file,TCSETAF,&newterm);
  959. X    read(file,&return_char,1);
  960. X  ioctl (file,TCSETAF,&oldterm);
  961. X  close(file);
  962. X    return (return_char);
  963. #endif
  964. #endif
  965. #endif
  966. }
  967. X
  968. X
  969. #ifdef __STDC__
  970. int edit_file(char *name,char *header)
  971. #else
  972. int edit_file(name,header)
  973. char *name, *header;
  974. #endif
  975. {
  976. X    char temp[80],temp2[80],choice;
  977. X    int end=0;
  978. X    FILE *fr;
  979. X
  980. X    sprintf (temp,"%s %s",edit_str,name);
  981. X    sprintf (temp2,"%s %s",edit_str,header);
  982. X    system(temp);
  983. X    while (!end)
  984. X    {
  985. X        printf("%sP%sost, %sE%sdit_file %sH%seader_edit or %sA%sbandon : ",
  986. X            scr(1,3,0),scr(1,6,0),
  987. X            scr(1,3,0),scr(1,6,0),
  988. X            scr(1,3,0),scr(1,6,0),scr(1,3,0),scr(1,6,0));
  989. X        fflush(stdout);
  990. X
  991. X        choice=ch_get();
  992. X        switch(choice)
  993. X        {
  994. X            case 'p':
  995. X            case 'P':
  996. X                /* Does the article exist ? */
  997. X                if ((fr=fopen(name,"r"))==NULL)
  998. X                    return(1);
  999. X                fclose(fr);
  1000. X                end = 1;
  1001. X                break;
  1002. X
  1003. X            case 'E':
  1004. X            case 'e':
  1005. X                system(temp);
  1006. X                break;
  1007. X
  1008. X            case 'H':
  1009. X            case 'h':
  1010. X                system(temp2);
  1011. X                break;
  1012. X
  1013. X            case 'a':
  1014. X            case 'A':
  1015. X                remove(name);
  1016. X                end = 2;
  1017. X        }
  1018. X    }
  1019. X    return( end-1 );
  1020. }
  1021. X
  1022. #ifdef __STDC__
  1023. unsigned long add_file (char *f1,char *f2)
  1024. #else
  1025. unsigned long add_file (f1,f2)
  1026. char *f1,*f2;
  1027. #endif
  1028. {
  1029. X    char header[80];
  1030. X    FILE *df1,*df2;
  1031. X    int c;
  1032. X    unsigned long length;
  1033. X    struct stat buf;
  1034. X
  1035. X    if ( ((df1=fopen(f1,"a"))==NULL) || ((df2=fopen(f2,"r"))==NULL) )
  1036. X    {
  1037. X        fprintf (stderr,"Unable to open a file [%s] or [%s]!\n",f1,f2);
  1038. X        return (0);
  1039. X    }
  1040. X
  1041. X    stat(f2,&buf);
  1042. X    length=(unsigned long)buf.st_size;
  1043. X    sprintf (header,"#! rnews %ld\n",length);
  1044. X    length += strlen(header);
  1045. X    fprintf (df1,"%s",header);
  1046. X
  1047. X    while ((c=fgetc(df2))!=EOF)
  1048. X        fputc(c,df1);
  1049. X
  1050. X    fclose(df1);
  1051. X    fclose(df2);
  1052. X    return(length);
  1053. }
  1054. X
  1055. X
  1056. /*
  1057. ** Append the content of the signature file to the file name
  1058. */
  1059. #ifdef __STDC__
  1060. void addsig(char *name)
  1061. #else
  1062. void addsig(name)
  1063. char *name;
  1064. #endif
  1065. {
  1066. X    FILE *fr,*fw;
  1067. X    char line[81];
  1068. X
  1069. X    if ((fr=fopen("sig.txt","r"))==NULL)
  1070. X        return;
  1071. X    if ((fw=fopen(name,"a"))==NULL)
  1072. X        return;
  1073. X    fprintf(fw,"\n-- \n");
  1074. X    while (fgets(line,80,fr)!=NULL)
  1075. X        fprintf(fw,"%s",line);
  1076. X    fclose(fr);
  1077. X    fclose(fw);
  1078. }
  1079. X
  1080. char *upperit(line)
  1081. char *line;
  1082. {
  1083. X    char *pos=line;
  1084. X    while (*pos)
  1085. X    {
  1086. X        *pos=toupper(*pos);
  1087. X        pos++;
  1088. X    }
  1089. X    return (line);
  1090. }
  1091. X
  1092. int get_set_unset(line)
  1093. char *line;
  1094. {
  1095. X    if( ( line[0]=='Y') || (line[0]=='y') || 
  1096. X        (line[0]=='S') || (line[0]=='s'))
  1097. X        return(SET);
  1098. X
  1099. X    if( ( line[0] == 'N' ) || ( line[0] == 'n' ) || 
  1100. X        (line[0]=='U') || (line[0]=='u'))
  1101. X        return(UNSET);
  1102. X
  1103. X    fprintf( stderr, "Error in config file: Line <%s>"
  1104. X        "should be either SET or UNSET\n",line);
  1105. X    return( -1 );
  1106. }
  1107. X
  1108. int get_set_unset_ask(line)
  1109. char *line;
  1110. {
  1111. X    if( ( line[0] == 'Y' ) || ( line[0] == 'y' ) || 
  1112. X        ( line[0] == 'S' ) || ( line[0] == 's' ) )
  1113. X        return(SET);
  1114. X
  1115. X    if( ( line[0] == 'N' ) || ( line[0] == 'n' ) || 
  1116. X        ( line[0] == 'U' ) || ( line[0] == 'u' ) )
  1117. X        return(UNSET);
  1118. X
  1119. X    if((line[0]=='A') || (line[0]=='a'))
  1120. X        return(ASK);
  1121. X    fprintf(stderr,"Error in config file: Line <%s>"
  1122. X        " should be either SET, UNSET or ASK\n",line);
  1123. X    return( -1 );
  1124. }
  1125. X
  1126. /*
  1127. ** Get a token from the token list out of the line
  1128. ** update pos as the position in the line after the token
  1129. ** and return the token number if found, -1 else.
  1130. */
  1131. #ifdef __STDC__
  1132. int get_token(char *line,char **tlist,char **pos)
  1133. #else
  1134. int get_token(line,tlist,pos)
  1135. char *line, **tlist,**pos;
  1136. #endif
  1137. {
  1138. X    int i=0,l,ll;
  1139. X    char *c;
  1140. X
  1141. X    /* search for the "=" separator */
  1142. X    c=strchr(line,'=');
  1143. X    if (c==NULL)
  1144. X        return (-1);
  1145. X    ll = (int)(c-line); /* Get line length */
  1146. X    *c='\0';
  1147. X    *pos=c+1; /* *pos points to the first character after the = */
  1148. X    upperit(line);
  1149. X    while (tlist[i][0])
  1150. X    {
  1151. X        l=strlen(tlist[i]);
  1152. X        if((l==ll) && (strcmp(line,tlist[i])==0))
  1153. X            return(i);
  1154. X        i++;
  1155. X    }
  1156. X    return(-1); /* failure */
  1157. }
  1158. X
  1159. /*
  1160. ** Open the slnr.ini file and read the config for
  1161. ** editor, ansi, pager, compress
  1162. */
  1163. void read_config()
  1164. {
  1165. X    FILE *fr;
  1166. X    int n;
  1167. X    char line[80],old_line[80],*pos;
  1168. X    static char *tlist[7]={"EDITOR",
  1169. X        "PAGER",
  1170. X        "COMPRESS",
  1171. X        "ANSI",
  1172. X        "LINES",
  1173. X        "QUOTE",
  1174. X        ""};
  1175. X
  1176. X    /*
  1177. X    ** Default
  1178. X    */
  1179. X
  1180. X    strcpy (edit_str,EDIT);
  1181. X    strcpy (pager_str,PAGER);
  1182. X    strcpy (compress_str,COMPRESS);
  1183. X    strcpy (quote_str,"> ");
  1184. X    use_ansi = SET;
  1185. X    Lines = 24;
  1186. X
  1187. X    if ((fr=fopen(INITFILE,"r"))==NULL)
  1188. X        return; /* No config file */
  1189. X    while (fgets(line,80,fr)!=NULL)
  1190. X    {
  1191. X        strcpy (old_line,line);
  1192. X        if (line[0]!='#' && line[0]!='\n') /* Ignore comments and blank lines */
  1193. X        {
  1194. X            if (line[strlen(line)-1]=='\n') /* Remove end CR */
  1195. X                line[strlen(line)-1]='\0';
  1196. X            switch (get_token(line,tlist,&pos))
  1197. X            {
  1198. X                case 0: /* EDITOR */
  1199. X                    strcpy (edit_str,pos);
  1200. X                    break;
  1201. X
  1202. X                case 1: /* PAGER */
  1203. X                    strcpy (pager_str,pos);
  1204. X                    break;
  1205. X
  1206. X                case 2: /* COMPRESS */
  1207. X                    strcpy (compress_str,pos);
  1208. X                    break;
  1209. X
  1210. X                case 3: /* Ansi */
  1211. X                    if( (n = get_set_unset(pos)) != -1 )
  1212. X                        use_ansi = n;
  1213. X                    break;
  1214. X
  1215. X                case 4: /* Lines */
  1216. X                    Lines = atoi(pos);
  1217. X                    if (Lines<5)
  1218. X                        Lines = 24;
  1219. X                    break;
  1220. X
  1221. X                case 5: /* Quote string */
  1222. X                    /* Skip the spaces */
  1223. X                    while ((*pos==' ') || (*pos=='\t'))
  1224. X                        pos++;
  1225. X
  1226. X                    if( *pos == '"')
  1227. X                    {
  1228. X                        strcpy(quote_str,pos+1);
  1229. X                        /* Find the matching double quote */
  1230. X                        pos = strrchr(quote_str,'"');
  1231. X                        if (pos)
  1232. X                            *pos = '\0';
  1233. X                    }
  1234. X                    else
  1235. X                        strcpy(quote_str,pos);
  1236. X                    remove_cr(quote_str);
  1237. X                    break;
  1238. X
  1239. X                default:
  1240. X                    fprintf(stderr,"Line <%s> has no keyword\n",old_line);
  1241. X                    break;
  1242. X            }
  1243. X        }
  1244. X    }
  1245. X    fclose(fr);
  1246. }
  1247. X
  1248. /*
  1249. ** Put the message pointed by fr into the filename and
  1250. ** returns the number of lines in the header
  1251. ** or 0 if an error occured
  1252. ** And quote the message with the quote string
  1253. */
  1254. X
  1255. int put_into_file(filename,fr,quote,flags,head)
  1256. char *filename;
  1257. FILE *fr;
  1258. char *quote;
  1259. struct header *head;
  1260. unsigned long flags;
  1261. {
  1262. X    FILE *fw;
  1263. X    int end=0,l,headermode=1,line_no=1,mail_flag=0;
  1264. X    char separator[80],line[255],mode[5];
  1265. X
  1266. X    strcpy( mode, "w" ); /* default */
  1267. X
  1268. X    if(( fw = fopen( filename, "r" ) ) != NULL )
  1269. X    {
  1270. X        fclose( fw );
  1271. X        printf( "File <%s> already exists\n", filename );
  1272. X        while( !end )
  1273. X        {
  1274. X            printf( "[A]ppend [O]verwrite [Q]uit:" );
  1275. X            fflush( stdout );
  1276. X            switch( ch_get() )
  1277. X            {
  1278. X                case 'q':
  1279. X                case 'Q':
  1280. X                    return(0);
  1281. X                
  1282. X                case 'a':
  1283. X                case 'A':
  1284. X                    strcpy( mode, "a" );
  1285. X                    end=1;
  1286. X                    break;
  1287. X
  1288. X                case 'O':
  1289. X                case 'o':
  1290. X                    strcpy( mode, "w" );
  1291. X                    end=1;
  1292. X                    break;
  1293. X            }
  1294. X        }
  1295. X    }
  1296. X
  1297. X    if((fw=fopen(filename, mode))==NULL)
  1298. X        return(0);
  1299. X
  1300. X    if(group[cur_grp].msg_type=='M')
  1301. X        strcpy(separator, MMDF_SEPARATOR);
  1302. X    else if(group[cur_grp].msg_type=='m')
  1303. X    {
  1304. X        strcpy(separator, "From ");
  1305. X        mail_flag = 1;
  1306. X    }
  1307. X    else
  1308. X        strcpy(separator,"#! rnews");
  1309. X    l = strlen(separator);
  1310. X
  1311. X    fgets(line,255,fr);
  1312. X    if (mail_flag)
  1313. X    {
  1314. X        if (!(flags & NO_HEADER))
  1315. X            fprintf (fw,"%s",line);
  1316. X        line_no++;
  1317. X        if( fgets( line, 255, fr ) == NULL )
  1318. X            return(0);
  1319. X    }
  1320. X
  1321. X    while( strncmp( line, separator, l ))
  1322. X    {
  1323. X        if( headermode )
  1324. X        {
  1325. X            if (!(flags & NO_HEADER))
  1326. X                fprintf (fw,"%s",line);
  1327. X            
  1328. X            if( (flags & GET_SUBJECT) && strncmp(line,"Subject: ",9)==0)
  1329. X                strcpy( head->subject, line+9);
  1330. X
  1331. X            if( (flags & GET_ID) && strncmp(line,"Message-ID: ",12)==0)
  1332. X                strcpy( head->id, line+12);
  1333. X
  1334. X            if( (flags & GET_FROM) && strncmp(line,"From: ",6)==0)
  1335. X                strcpy( head->from, line+6);
  1336. X
  1337. X            if( (flags & GET_REPLYTO) && strncmp(line,"Reply-To: ",10)==0)
  1338. X                strcpy( head->replyto, line+10);
  1339. X        }
  1340. X        else
  1341. X        {
  1342. X            fprintf( fw,"%s%s",quote,line);
  1343. X            line_no++;
  1344. X        }
  1345. X
  1346. X        if (line[0]=='\n') /* End of header */
  1347. X            headermode=0;
  1348. X
  1349. X        if(fgets(line,255,fr)==NULL)
  1350. X            break;
  1351. X    }
  1352. X    fclose(fw);
  1353. X    return(line_no);
  1354. }
  1355. X
  1356. void show_menu(tof,eof)
  1357. unsigned int tof,eof;
  1358. {
  1359. X    printf ("\n%sA%sgain %sV%siew %sM%sail ",
  1360. X        scr(1,3,0),scr(1,6,0),scr(1,3,0),scr(1,6,0),scr(1,3,0),scr(1,6,0));
  1361. X    if (group[cur_grp].msg_type=='u')
  1362. X    /* No follow-up for private mail */
  1363. X        printf ("%sW%srite ",scr(1,3,0),scr(1,6,0));
  1364. X    if (!eof)
  1365. X        printf ("%sn%sext_pg ",
  1366. X            scr(1,3,0),scr(1,6,0));
  1367. X    if (!tof)
  1368. X        printf ("%sp%srev_pg ",
  1369. X            scr(1,3,0),scr(1,6,0));
  1370. X    printf ("%sN%sext_grp %sP%srev_grp %sS%save %sH%slp %sQ%suit ",
  1371. X            scr(1,3,0),scr(1,6,0),
  1372. X            scr(1,3,0),scr(1,6,0),
  1373. X            scr(1,3,0),scr(1,6,0),
  1374. X            scr(1,3,0),scr(1,6,0),
  1375. X            scr(1,3,0),scr(1,6,0));
  1376. X    printf("%s", scr(1, WHITE, 0));
  1377. X    fflush(stdout);
  1378. }
  1379. X
  1380. void display_page_again(line_no)
  1381. unsigned int line_no;
  1382. {
  1383. X    int i,j;
  1384. X
  1385. X    show_header();
  1386. X    cur_art=old_cur_art;
  1387. X    for (j=0;j<cur_line;j++)
  1388. X    {
  1389. X        disp_f(&article[cur_art]);
  1390. X        cur_art++;
  1391. X    }
  1392. X    if (cur_line!=line_no)
  1393. X    {
  1394. X        for (i=cur_line; i<=line_no; i++)
  1395. X            printf("\n");
  1396. X    }
  1397. }
  1398. X
  1399. /*
  1400. ** Get a clean address to be passed back to the mailer
  1401. */
  1402. char *clean_to( to )
  1403. char *to;
  1404. {
  1405. X    char *pos1, *pos2;
  1406. X
  1407. X    /*
  1408. X    ** Remove the comment between ()
  1409. X    */
  1410. X    if( (pos1 = strchr( to, '(' )) != NULL )
  1411. X    {
  1412. X        if( (pos2=strrchr(pos1,')')) != NULL )
  1413. X            strcpy( pos1, pos2+1 );
  1414. X        else
  1415. X            *pos1 = '\0';
  1416. X    }
  1417. X    /*
  1418. X    ** Get the address between <>
  1419. X    */
  1420. X    if( (pos1 = strchr( to, '<' )) != NULL )
  1421. X    {
  1422. X        strcpy( to, pos1+1 );
  1423. X        if( (pos2 = strchr( to, '>' )) != NULL )
  1424. X            *pos2 = '\0';
  1425. X    }
  1426. X    return( to );
  1427. }
  1428. X
  1429. int main()
  1430. {
  1431. X    unsigned int count, line_no,i=0,j=0,end=0,eof=0;
  1432. X    unsigned int reply_created=0,ret;
  1433. X    unsigned int tof=1,redisplay=1,Max_grp,Max_art,mail_reply_no=0;
  1434. X    char line[255],temp[80],choice,value[80],file_list[255];
  1435. X    char To[80],Replyto[80],From[80];
  1436. X    char Reply[80],subjectline[80],msgidline[80];
  1437. X    char art_save_name[80],shell_cmd_name[80];
  1438. X    FILE *fr,*fw;
  1439. X    struct header head;
  1440. X
  1441. #ifdef ATARI
  1442. X    initialise_atari();
  1443. #endif
  1444. X
  1445. #ifdef __MSDOS__           /* Text must be translated so if user edits INI    */
  1446. X    _fmode = O_TEXT ;    /* file with an MS-DOS editor, command lines    */
  1447. #endif                    /* won't be truncated with \r                    */
  1448. X
  1449. X    read_config();
  1450. X
  1451. #ifdef __MSDOS__         /* Unix-type files must not be translated so     */
  1452. X    _fmode = O_BINARY ;    /* that pointers inside them are valid.            */
  1453. #endif
  1454. X
  1455. X    To[0]=Replyto[0]=From[0]=art_save_name[0]=shell_cmd_name[0]='\0';
  1456. X    cls();
  1457. X    printf ("\n%sS%simple %sL%socal %sN%sews %sR%seader. V 2.0a (c) 1993 Philippe
  1458.  Goujard\n",
  1459. X        scr(1,3,0),scr(1,6,0),
  1460. X        scr(1,3,0),scr(1,6,0),
  1461. X        scr(1,3,0),scr(1,6,0),
  1462. X        scr(1,3,0),scr(1,6,0));
  1463. X    /*
  1464. X    ** To be changed when we have another compressor
  1465. X    */
  1466. X    sprintf (Reply,"REPLY.zip");
  1467. X    if ((fr=fopen(Reply,"r"))!=NULL)
  1468. X    {
  1469. X        fclose (fr);
  1470. X        printf ("\nA Reply packet already exists. Keep it (Y/n) ? ");
  1471. X        fflush(stdout);
  1472. X        choice=ch_get();
  1473. X        if (choice=='n' || choice=='N')
  1474. X            remove (Reply);
  1475. X        fflush(stdin);
  1476. X    }
  1477. X    for (i=0; i<MAXGRP; group[i++].reply=0)
  1478. X        ;
  1479. X
  1480. X    index_all();
  1481. X
  1482. X    Max_grp=cur_grp-1;
  1483. X    Max_art=cur_art;   /* Not needed in this version */
  1484. X
  1485. X    cur_art=0;
  1486. X    cur_grp=0;
  1487. X
  1488. #ifdef INFOCOM
  1489. X    /*
  1490. X    ** This is only done with Infocom where a user can define a profile which
  1491. X    ** is independant of the Unix environment. It can be easily changed to a
  1492. X    ** "GETENV"
  1493. X    */
  1494. X    if (get_prof("LINES",value)>0)
  1495. X    {
  1496. X        line_no = atoi(value)-6;
  1497. X        if (line_no < 7)
  1498. X            line_no=18;
  1499. X    }
  1500. #else
  1501. X    line_no = Lines-6;
  1502. #endif
  1503. X    /* Displays header */
  1504. X    show_header();
  1505. X
  1506. X    /* Displays list upto LINES - 6 */
  1507. X    i=0;
  1508. X
  1509. X    while ((cur_line<line_no) && cur_line<group[cur_grp].art)
  1510. X    {
  1511. X        disp_f(&article[cur_art]);
  1512. X        cur_line++;
  1513. X        cur_art++;
  1514. X    }
  1515. X    if (cur_line!=line_no)
  1516. X    {
  1517. X        eof=1;
  1518. X        for (i=cur_line; i<=line_no; i++)
  1519. X            printf("\n");
  1520. X    }
  1521. X
  1522. X    /*
  1523. X    ** MAIN LOOP
  1524. X    */
  1525. X    while (!end)
  1526. X    {
  1527. X        /* Displays footer */
  1528. X        if (redisplay)
  1529. X            show_menu( tof, eof);
  1530. X
  1531. X        choice=ch_get();
  1532. X        redisplay=1;
  1533. X        switch (choice)
  1534. X        {
  1535. X            case 'A':
  1536. X            case 'a':
  1537. X                display_page_again(line_no);
  1538. X                break;
  1539. X
  1540. X            case 'n': /* Next page */
  1541. X                if (eof)
  1542. X                    redisplay=0;
  1543. X                else
  1544. X                {
  1545. X                    tof=0;
  1546. X                    show_header();
  1547. X                    cur_line=1;
  1548. X                    old_cur_art=cur_art;
  1549. X                    while ((cur_line<line_no) &&
  1550. X                        (article[cur_art].rank+1 < group[cur_grp].art))
  1551. X                    {
  1552. X                        disp_f(&article[cur_art]);
  1553. X                        cur_line++;
  1554. X                        cur_art++;
  1555. X                    }
  1556. X                    disp_f(&article[cur_art++]);
  1557. X                    if (cur_line!=line_no)
  1558. X                    {
  1559. X                        eof=1;
  1560. X                        for (i=cur_line; i<=line_no; i++)
  1561. X                            printf("\n");
  1562. X                    }
  1563. X                    else
  1564. X                        eof=0;
  1565. X                }
  1566. X                break;
  1567. X
  1568. X            case 'p': /* Previous page */
  1569. X                if (tof)
  1570. X                    redisplay=0;
  1571. X                else
  1572. X                {
  1573. X                    eof=0;
  1574. X                    show_header();
  1575. X                    cur_art = old_cur_art - line_no;
  1576. X                    old_cur_art = cur_art;
  1577. X                    if (article[cur_art].rank==0)
  1578. X                        tof=1;
  1579. X                    else
  1580. X                        tof=0;
  1581. X                    for (cur_line=0; cur_line<line_no; cur_line++)
  1582. X                    {
  1583. X                        disp_f(&article[cur_art]);
  1584. X                        cur_art++;
  1585. X                    }
  1586. X                }
  1587. X                break;
  1588. X
  1589. X            case 'N': /* Next group */
  1590. X            case '>':
  1591. X                no = 0;
  1592. X                cur_grp++;
  1593. X                if (cur_grp>Max_grp)
  1594. X                    cur_grp=0;
  1595. X                cur_line=0;
  1596. X                eof=0;
  1597. X                tof=1;
  1598. X                show_header();
  1599. X                cur_art=group[cur_grp].start;
  1600. X                old_cur_art=cur_art;
  1601. X                while ((cur_line<line_no) && cur_line<group[cur_grp].art)
  1602. X                {
  1603. X                    disp_f(&article[cur_art]);
  1604. X                    cur_line++;
  1605. X                    cur_art++;
  1606. X                }
  1607. X                if (cur_line!=line_no)
  1608. X                {
  1609. X                    eof=1;
  1610. X                    for (i=cur_line; i<=line_no; i++)
  1611. X                        printf("\n");
  1612. X                }
  1613. X                break;
  1614. X
  1615. X            case 'P': /* Prev group */
  1616. X            case '<':
  1617. X                no = 0;
  1618. X                if (cur_grp == 0)
  1619. X                    cur_grp=Max_grp;
  1620. X                else
  1621. X                    cur_grp--;
  1622. X                cur_line=0;
  1623. X                eof=0;
  1624. X                tof=1;
  1625. X                cur_art=group[cur_grp].start;
  1626. X                old_cur_art=cur_art;
  1627. X                show_header();
  1628. X                while ((cur_line<line_no) && cur_line<group[cur_grp].art)
  1629. X                {
  1630. X                    disp_f(&article[cur_art]);
  1631. X                    cur_line++;
  1632. X                    cur_art++;
  1633. X                }
  1634. X                if (cur_line!=line_no)
  1635. X                {
  1636. X                    eof=1;
  1637. X                    for (i=cur_line; i<=line_no; i++)
  1638. X                        printf("\n");
  1639. X                }
  1640. X                break;
  1641. X
  1642. X            case 'H':
  1643. X            case 'h':
  1644. X                cls();
  1645. X                /*
  1646. X                ** Help doesnt help much at the moment
  1647. X                ** Well, c'est la vie...
  1648. X                */
  1649. X                printf ("A : redisplay the same page\n"
  1650. X                          "n : Display next page\n"
  1651. X                                "p : Display previous page \n"
  1652. X                                "N or > : Go to next Newsgroup\n"
  1653. X                                "P or < : Go to previous Newsgroup\n"
  1654. X                                "v : View an article\n"
  1655. X                                "V : Display an article with its full header\n"
  1656. X                                "M : Send a new mail or Reply to an article by mail\n"
  1657. X                                "W : Write an article or a follow-up to an article\n"
  1658. X                                "SPACE : Display the next article\n"
  1659. X                                "s : Save an article to a filename\n"
  1660. X                                "S : Save an article without the header\n"
  1661. X                                "! : Execute a shell command\n"
  1662. X                                "Q : Quit \n\n");
  1663. X                break;
  1664. X
  1665. X            case 'Q':
  1666. X            case 'q':
  1667. X                printf ("\n"); /* To have the prompt on a new line */
  1668. X                end=1;
  1669. X                file_list[0]='\0';
  1670. X                /*
  1671. X                ** Compress the R*.MSG files
  1672. X                */
  1673. X                if (reply_created)
  1674. X                {
  1675. X                    /*
  1676. X                    ** For each newsgroup where there is a reply
  1677. X                    ** Add an entry to the REPLIES file
  1678. X                    ** The field "reply" is set only for "follow-up" or "posts"
  1679. X                    ** Not for mails or replies by mail to the author.
  1680. X                    */
  1681. X                    if ((fw=fopen("REPLIES","w"))==NULL)
  1682. X                        exit(1);
  1683. X                    for (i=0;i<MAXGRP;i++)
  1684. X                    {
  1685. X                        if(group[i].reply)
  1686. X                        {
  1687. X                            fprintf(fw,"R%s\tnews\t%cn\t%d\n",
  1688. X                                group[i].prefix,
  1689. X                                group[i].msg_type,
  1690. X                                group[i].reply);
  1691. X                                /*
  1692. X                                ** Add the filename to the list of files
  1693. X                                ** to compress
  1694. X                                */
  1695. X                                sprintf(temp,"R%s%s ",group[i].prefix,NEWSTXT);
  1696. X                                strcat(file_list,temp);
  1697. X                        }
  1698. X                    }
  1699. X                    fclose(fw);
  1700. X                }
  1701. X                /*
  1702. X                ** Now look if any mail reply was created too
  1703. X                */
  1704. X                if ((fr=fopen("RMAIL.MSG","r"))!=NULL)
  1705. X                {
  1706. X                    fclose(fr);
  1707. X                    fw=fopen("REPLIES","a");
  1708. X                    fprintf(fw,"RMAIL\tmail\tun\t%d\n", mail_reply_no);
  1709. X                    sprintf(temp,"RMAIL%s ",NEWSTXT);
  1710. X                    strcat(file_list,temp);
  1711. X                    fclose(fw);
  1712. X                }
  1713. X                if (file_list[0])
  1714. X                {
  1715. X                    sprintf (temp,"%s %s REPLIES %s",compress_str,Reply,file_list);
  1716. X                    system (temp);
  1717. X                }
  1718. X
  1719. #ifdef ATARI
  1720. X                closedown_atari();
  1721. #endif
  1722. X                break;
  1723. X
  1724. X            case 'V':
  1725. X            case 'v':
  1726. X                printf ("\n");
  1727. X                sprintf (value,"%d",no+1);
  1728. X                fgetstr("No >",temp,value,4,stdin);
  1729. X                no = atoi(temp);
  1730. showit:
  1731. X                if ((no>0) && (no <= group[cur_grp].art))
  1732. X                {
  1733. X                    sprintf(temp,"%s%s",group[cur_grp].prefix,NEWSTXT);
  1734. X                    fr=fopen(temp,"r");
  1735. X                    /* Get the starting article number */
  1736. X                    count=group[cur_grp].start+no-1;
  1737. X
  1738. X                    /* save the article into a temp file */
  1739. X                    fseek(fr, article[count].ptr, 0);
  1740. X                    put_into_file("art.tmp",fr,"",
  1741. X                            (choice=='V') ? 0L : NO_HEADER, 
  1742. X                            (struct header *)NULL);
  1743. X                    fclose(fr);
  1744. X
  1745. X                    sprintf (temp,"%s %s",pager_str,"art.tmp");
  1746. X                    system(temp);
  1747. X                    remove("art.tmp");
  1748. X                    /*
  1749. X                    ** Show the list again
  1750. X                    */
  1751. X                    show_header();
  1752. X                    cur_art=old_cur_art;
  1753. X                    for (j=0;j<cur_line;j++)
  1754. X                    {
  1755. X                        disp_f(&article[cur_art]);
  1756. X                        cur_art++;
  1757. X                    }
  1758. X                    if (cur_line!=line_no)
  1759. X                    {
  1760. X                        eof=1;
  1761. X                        for (i=cur_line; i<=line_no; i++)
  1762. X                            printf("\n");
  1763. X                    }
  1764. X                }
  1765. X                break;
  1766. X
  1767. X            case ' ':
  1768. X                if(no < group[cur_grp].art)
  1769. X                    no++;
  1770. X                goto showit;
  1771. X
  1772. X            case 'M': /* Mail somebody */
  1773. X            case 'm':
  1774. X                printf ("\n%sN%sew message or %sR%sesponse ?",
  1775. X                    scr(1,3,0),scr(1,6,0),scr(1,3,0),scr(1,6,0));
  1776. X                fflush(stdout);
  1777. X                choice=ch_get();
  1778. X                printf ("\n");
  1779. X                subjectline[0]='\0';
  1780. X                if (choice=='r' || choice=='R')
  1781. X                {
  1782. X                    /* Ask to which mail */
  1783. X                    sprintf (value,"%d",no);
  1784. X                    fgetstr("Reply to No >",temp,value,4,stdin);
  1785. X                    no=atoi(temp);
  1786. X                    if ((no>0) && (no <= group[cur_grp].art) )
  1787. X                    {
  1788. X                        /*
  1789. X                        ** Get article and quote it
  1790. X                        */
  1791. X                        sprintf(temp,"%s%s",group[cur_grp].prefix,NEWSTXT);
  1792. X                        fr=fopen(temp,"r");
  1793. X                        count=group[cur_grp].start+no-1;
  1794. X                        fseek(fr, article[count].ptr, 0);
  1795. X
  1796. X                        /* save the article into a temp file */
  1797. X                        head.subject = line;
  1798. X                        head.from = From;
  1799. X                        head.replyto = Replyto;
  1800. X
  1801. X                        ret = put_into_file( "ed0.tmp",fr, quote_str,
  1802. X                            NO_HEADER | GET_SUBJECT | GET_FROM | GET_REPLYTO, &head);
  1803. X                        fclose(fr);
  1804. X
  1805. X                        if( ret == 0 )
  1806. X                        {
  1807. X                            perror( "Unable to write temp file" );
  1808. X                            break;
  1809. X                        }
  1810. X
  1811. X                        /* Does the subject line begin with "Re" ? */
  1812. X                        remove_cr( line);
  1813. X                        if (strncmp(line,"Re",2)==0)
  1814. X                            sprintf(subjectline,"%s",line);
  1815. X                        else
  1816. X                            sprintf(subjectline,"Re: %s",line);
  1817. X
  1818. X                        if (*Replyto)
  1819. X                            strcpy( To, Replyto);
  1820. X                        else if (*From)
  1821. X                            strcpy( To, From);
  1822. X                        remove_cr( To );
  1823. X                        clean_to( To );
  1824. X
  1825. X                        /*
  1826. X                        ** Add the group in the body of the quoted article
  1827. X                        */
  1828. X                        remove_cr(From);
  1829. X                        fr = fopen( "ed0.tmp","r" );
  1830. X                        fw = fopen( "edit.tmp","w" );
  1831. X                        fprintf( fw, "In %s you wrote:\n", group[cur_grp].name);
  1832. X                        while( fgets(line,255,fr)!=NULL )
  1833. X                        {
  1834. X                            fprintf( fw, "%s", line );
  1835. X                        }
  1836. X                        fclose( fr );
  1837. X                        fclose( fw );
  1838. X                        remove( "ed0.tmp" );
  1839. X                    }
  1840. X                }
  1841. X                /* Print the header first */
  1842. X                fw=fopen ("article.tmp","w");
  1843. X                if (fw==NULL)
  1844. X                    break;
  1845. X
  1846. X                if (!*To)
  1847. X                    fgetstr("To >",To,"",60,stdin);
  1848. X                fgetstr("Subject >",temp,subjectline,60,stdin);
  1849. X                fprintf (fw,"To: %s\n",To);
  1850. X                fprintf (fw,"Subject: %s\n",temp);
  1851. X                fclose(fw);
  1852. X                To[0]=From[0]=Replyto[0]='\0';
  1853. X
  1854. X                if (edit_file("edit.tmp","article.tmp"))
  1855. X                    remove("article.tmp");
  1856. X                else
  1857. X                {
  1858. X                    /* Add the signature */
  1859. X                    addsig("edit.tmp");
  1860. X
  1861. X                    /* Concatenate article.tmp and edit.tmp */
  1862. X                    fr=fopen("edit.tmp","r");
  1863. X                    fw=fopen("article.tmp","a");
  1864. X                    fprintf (fw,"\n"); /* End of header */
  1865. X                    while (fgets(line,255,fr)!=NULL)
  1866. X                        fprintf(fw,"%s",line);
  1867. X                    fclose(fr);
  1868. X                    fclose(fw);
  1869. X                    remove("edit.tmp");
  1870. X
  1871. X                    /*
  1872. X                    ** Add article.tmp to the RMAIL.MSG file
  1873. X                    */
  1874. X                    sprintf (temp,"RMAIL%s",NEWSTXT);
  1875. X                    add_file(temp,"article.tmp");
  1876. X                    remove("article.tmp");
  1877. X                    mail_reply_no++;
  1878. X                }
  1879. X                /* Then redisplay the list */
  1880. X                display_page_again(line_no);
  1881. X                break;
  1882. X
  1883. X            case 'W': /* write article or follow-up */
  1884. X            case 'w':
  1885. X                if( group[cur_grp].msg_type != 'u')
  1886. X                    break;
  1887. X
  1888. X                printf ("\n%sN%sew article or %sF%sollow-up ?",
  1889. X                    scr(1,3,0),scr(1,6,0),scr(1,3,0),scr(1,6,0));
  1890. X                choice=ch_get();
  1891. X                printf ("\n");
  1892. X                subjectline[0]='\0';
  1893. X                msgidline[0]='\0';
  1894. X                if (choice=='f' || choice=='F')
  1895. X                {
  1896. X                    /*
  1897. X                    ** Follow-up.
  1898. X                    ** Ask to which article
  1899. X                    */
  1900. X                    sprintf (value,"%d",no);
  1901. X                    fgetstr("Follow up to No >",temp,value,4,stdin);
  1902. X                    no=atoi(temp);
  1903. X                    if ((no>0) && (no <= group[cur_grp].art)
  1904. X                        && (group[cur_grp].msg_type=='u'))
  1905. X                    {
  1906. X                        /*
  1907. X                        ** Get article and quote it
  1908. X                        */
  1909. X                        sprintf(temp,"%s%s",group[cur_grp].prefix,NEWSTXT);
  1910. X                        fr=fopen(temp,"r");
  1911. X                        count=group[cur_grp].start+no-1;
  1912. X                        fseek(fr, article[count].ptr, 0);
  1913. X
  1914. X                        /* 
  1915. X                        ** save the article into a temp file
  1916. X                        */
  1917. X                        head.subject = line;
  1918. X                        head.id = msgidline;
  1919. X                        head.from = From;
  1920. X
  1921. X                        ret = put_into_file( "ed0.tmp",fr, quote_str,
  1922. X                            NO_HEADER | GET_SUBJECT | GET_ID | GET_FROM, &head);
  1923. X                        fclose(fr);
  1924. X                        if( ret == 0 )
  1925. X                        {
  1926. X                            perror( "Unable to write temp file" );
  1927. X                            break;
  1928. X                        }
  1929. X
  1930. X                        remove_cr(line);
  1931. X                        if (strncmp(line,"Re",2)==0)
  1932. X                            sprintf(subjectline,"%s",line);
  1933. X                        else
  1934. X                            sprintf(subjectline,"Re: %s",line);
  1935. X
  1936. X                        /*
  1937. X                        ** Add the author name and group in the body 
  1938. X                        ** of the quoted article
  1939. X                        */
  1940. X                        remove_cr(From);
  1941. X                        fr = fopen( "ed0.tmp","r" );
  1942. X                        fw = fopen( "edit.tmp","w" );
  1943. X                        fprintf( fw, "%s wrote:\n", From);
  1944. X                        while( fgets(line,255,fr)!=NULL )
  1945. X                        {
  1946. X                            fprintf( fw, "%s", line );
  1947. X                        }
  1948. X                        fclose( fr );
  1949. X                        fclose( fw );
  1950. X                        remove( "ed0.tmp" );
  1951. X
  1952. X                    }
  1953. X                }
  1954. X                /* Print the header first */
  1955. X                fw=fopen ("article.tmp","w");
  1956. X                if (fw==NULL)
  1957. X                    break;
  1958. X
  1959. X                fflush(stdin);
  1960. X                fgetstr("Subject >",temp,subjectline,60,stdin);
  1961. X                fprintf (fw,"Newsgroups: %s\n",group[cur_grp].name);
  1962. X                fprintf (fw,"Subject: %s\n",temp);
  1963. X
  1964. X                /* If its a follow-up, add reference to help threading */
  1965. X                if (msgidline[0])
  1966. X                    fprintf (fw,"References: %s",msgidline);
  1967. X
  1968. X                fclose(fw);
  1969. X
  1970. X                if (edit_file("edit.tmp","article.tmp"))
  1971. X                    remove("article.tmp");
  1972. X                else
  1973. X                {
  1974. X                    /* Add the signature */
  1975. X                    addsig("edit.tmp");
  1976. X
  1977. X                    /* Concatenate article.tmp and edit.tmp */
  1978. X                    fr = fopen( "edit.tmp", "r");
  1979. X                    fw = fopen( "article.tmp", "a");
  1980. X                    fprintf( fw,"\n" ); /* End of header */
  1981. X                    while( fgets(line,255,fr)!=NULL )
  1982. X                        fprintf( fw,"%s",line );
  1983. X                    fclose(fr);
  1984. X                    fclose(fw);
  1985. X                    remove("edit.tmp");
  1986. X                    /*
  1987. X                    ** Add article.tmp to the reply file
  1988. X                    */
  1989. X                    sprintf (temp,"R%s%s",group[cur_grp].prefix,NEWSTXT);
  1990. X                    add_file(temp,"article.tmp");
  1991. X                    remove("article.tmp");
  1992. X                    reply_created++;
  1993. X                    group[cur_grp].reply++;
  1994. X                }
  1995. X                /* Then redisplay the list */
  1996. X                display_page_again(line_no);
  1997. X                break;
  1998. X            
  1999. X            case 's': /* Save article */
  2000. X            case 'S': /* Save with no header */
  2001. X                printf("\n");
  2002. X
  2003. X                /* Get article number */
  2004. X                sprintf (value,"%d",no);
  2005. X                fgetstr("Save article No >",temp,value,4,stdin);
  2006. X                no=atoi(temp);
  2007. X
  2008. X                /* If the number is within range */
  2009. X                if ((no>0) && (no <= group[cur_grp].art))
  2010. X                {
  2011. X
  2012. X                    /* Get file name */
  2013. X                    fgetstr("Save article in:",temp,art_save_name,30,stdin);
  2014. X                    if ( temp[0] )
  2015. X                    {
  2016. X                        strcpy(art_save_name, temp);
  2017. X
  2018. X                        sprintf(temp,"%s%s",group[cur_grp].prefix,NEWSTXT);
  2019. X                        fr=fopen(temp,"r");
  2020. X                        count=group[cur_grp].start+no-1;
  2021. X                        fseek(fr, article[count].ptr, 0);
  2022. X
  2023. X                        /* 
  2024. X                        ** save the article into a temp file 
  2025. X                        */
  2026. X                        if (!put_into_file( art_save_name, fr, "", 
  2027. X                            (choice=='S') ? NO_HEADER : 0L, 
  2028. X                            (struct header *)NULL))
  2029. X                            perror("Unable to save article");
  2030. X                        fclose(fr);
  2031. X                    }
  2032. X                }
  2033. X                /* Then redisplay the list */
  2034. X                display_page_again(line_no);
  2035. X                break;
  2036. X            
  2037. X            case '!':
  2038. X                printf( "\n" );
  2039. X                fgetstr("Shell cmd:",temp,shell_cmd_name,30,stdin);
  2040. X                if ( temp[0] )
  2041. X                {
  2042. X                    strcpy( shell_cmd_name, temp );
  2043. X                    system( temp );
  2044. X                    printf( "Press any key to return to SLNR" );
  2045. X                    fflush( stdout );
  2046. X                    ch_get();
  2047. X                }
  2048. X                display_page_again(line_no);
  2049. X                break;
  2050. X
  2051. X
  2052. X            default:
  2053. X                redisplay=0;
  2054. X                break;
  2055. X
  2056. X        }
  2057. X    }
  2058. X    return(0);
  2059. }
  2060. SHAR_EOF
  2061. chmod 0440 slnr/slnr.c ||
  2062. echo 'restore of slnr/slnr.c failed'
  2063. Wc_c="`wc -c < 'slnr/slnr.c'`"
  2064. test 39079 -eq "$Wc_c" ||
  2065.     echo 'slnr/slnr.c: original size 39079, current size' "$Wc_c"
  2066. rm -f _shar_wnt_.tmp
  2067. fi
  2068. # ============= slnr/slnr.doc ==============
  2069. if test -f 'slnr/slnr.doc' -a X"$1" != X"-c"; then
  2070.     echo 'x - skipping slnr/slnr.doc (File already exists)'
  2071.     rm -f _shar_wnt_.tmp
  2072. else
  2073. > _shar_wnt_.tmp
  2074. echo 'x - extracting slnr/slnr.doc (Text)'
  2075. sed 's/^X//' << 'SHAR_EOF' > 'slnr/slnr.doc' &&
  2076. # SCCS header
  2077. # File    : slnr.doc
  2078. # Version : 1.4
  2079. X
  2080. ===============================================================================
  2081.  
  2082. X
  2083. X         _/_/_/_/     _/            _/        _/    _/_/_/_/_/
  2084. X        _/      _/    _/            _/_/      _/    _/       _/
  2085. X        _/            _/            _/ _/     _/    _/        _/
  2086. X          _/_/_/      _/            _/  _/    _/    _/_/_/_/_/
  2087. X               _/     _/            _/   _/   _/    _/      _/
  2088. X        _/      _/    _/            _/    _/  _/    _/       _/
  2089. X         _/_/_/       _/_/_/_/_/    _/     _/ _/    _/        _/
  2090. X
  2091. X        Simple Local News Reader. V 2.1b (c) 1993 Philippe Goujard
  2092. ===============================================================================
  2093.  
  2094. X
  2095. SLNR is a program to read Usenet news on your local machine,
  2096. also called an off-line newsreader.
  2097. X
  2098. SLNR is THE off-line news reader that implements the SLNP format for
  2099. exchanging electronic mail and usenet news messages between a usenet site
  2100. (typically Unix) and your local machine. 
  2101. X
  2102. The SLNP packet format is in the public domain and should be widely
  2103. available. Check for file "slnp.fmt".
  2104. X
  2105. X
  2106. X
  2107. X
  2108. Why SLNR ?
  2109. ~~~~~~~~~~
  2110. X  - There is a growing market of people who want to read usenet news on 
  2111. X  their local (dos/amiga/atari/mac) machine.
  2112. X  
  2113. X  - For the moment they have the choice between getting a "feed" from a unix 
  2114. X  site and installing one of the uucp packages (waffle, fsuucp...) or 
  2115. X  getting a tcp/ip connection. None of them is easy for beginners.
  2116. X  
  2117. X  - Many people know the bbs world and are familiar with QWK off-line mail 
  2118. X  readers and want something similar.
  2119. X
  2120. Some vocabulary
  2121. ~~~~~~~~~~~~~~~
  2122. X   The messages you are about to read are divided in two categories : your
  2123. X   private mail and usenet news messages (or posts).
  2124. X
  2125. X   For people who come from the fidonet world this may be a little bit
  2126. X   confusing at first since on most fido bbs, "private mail" could be mixed
  2127. X   within public messages. Here private and public are totally separated.
  2128. X
  2129. X   The news messages are grouped in "newsgroups" they are the equivalent of
  2130. X   what you can know as "mail area", "conference", "forum" or "continuum".
  2131. X   The groups are sorted in a hierarchy : for example all "comp.*" groups
  2132. X   are for computer subjects, all "rec.*" for recreational subjects. And
  2133. X   "comp.lang.*" will be all the computer langages etc...
  2134. X
  2135. X   Most of those groups are shared among thousands of machines and millions
  2136. X   of readers in the world. This distribution is done by multiple ways,
  2137. X   some of it being by modem over phone line other being on dedicated fast
  2138. X   lines. 
  2139. X   When you read a message on your machine there is a good chance that
  2140. X   several thousand other readers have done that already and that many
  2141. X   answers have already been posted.
  2142. X
  2143. X   There are several rules that you should bear in mind when you want to
  2144. X   post a message to the net : those rules are called "nettiquette". It is
  2145. X   not within the scope of this documentation to expose the nettiquette but
  2146. X   if you are looking for pointers, have a look in newsgrpoups like :
  2147. X   "news.announce.newusers" "news.newsusers.questions" or "news.answers".
  2148. X
  2149. X
  2150. 1) Installation & configuration
  2151. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2152. X    To install SLNR you need to create a subdirectory where you put the
  2153. X    executable. You will later in that directory put the files extracted 
  2154. X    from the SLNP packet.(*.MSG, AREAS, *.IDX etc...)
  2155. X
  2156. X    You can also create in that directory a file called "sig.txt" this is
  2157. X    your signature that will be appended when you write a usenet message or
  2158. X    an electonic mail. Usually it should be one or two lines with you email
  2159. X    or postal address.
  2160. X
  2161. X    The configuration file is called "slnr.ini". It is not mandatory to
  2162. X    have one. The configuration file contains lines of the form :
  2163. X    VARIABLE=value
  2164. X    where VARIABLE can be one of the following fields:
  2165. X
  2166. X    Field  : PAGER
  2167. X    Value  : string
  2168. X    Default: See apendix B
  2169. X    Comment: This is the name of the external program that will be used to
  2170. X    display a message.
  2171. X
  2172. X    Field  : EDITOR
  2173. X    Value  : string
  2174. X    Default: See apendix B
  2175. X    Comment: This is the name of the external program that will be used to
  2176. X    edit messages and posts.
  2177. X
  2178. X    Field  : COMPRESS
  2179. X    Value  : string
  2180. X    Default: See apendix B
  2181. X    Comment: This is the name of the compactor program that will be used to
  2182. X    compress replies.
  2183. X
  2184. X    Field  : ANSI
  2185. X    Value  : SET or UNSET
  2186. X    Default: SET
  2187. X    Comment: If SET, ansi color codes will be sent to the screen for the 
  2188. X    MSDOS version (an ANSI.SYS or equivalent driver need to be loaded).
  2189. X
  2190. X    Field  : LINES
  2191. X    Value  : Integer
  2192. X    Default: 24
  2193. X    Comment: This is the number of lines your screen can display. Under
  2194. X    MSDOS, changing this value does NOT put the screen in any specific
  2195. X    mode. This has to be done externally to SLNR.
  2196. X
  2197. X    Field  : QUOTE
  2198. X    Value  : String
  2199. X    Default: "> "
  2200. X    Comment: This string will be added in front of mail answers or
  2201. X    follow-up messages in order to quote the message you are replying to.
  2202. X    Note that the double quotes are only mandatory if you want to include a
  2203. X    space character in the string.
  2204. X
  2205. X    Example:
  2206. X
  2207. # This is the SLNR config file
  2208. #
  2209. # Each line starting with a hash is a comment
  2210. #
  2211. # The config file is not necessary, if not found SLNR will use the 
  2212. # defaults values.
  2213. X
  2214. EDITOR=C:\MSDOS\QEDIT
  2215. PAGER=c:\tools\list
  2216. X
  2217. COMPRESS=pkzip
  2218. X
  2219. # Un-comment the following if you don't want ansi color codes
  2220. # ANSI=No
  2221. X
  2222. X
  2223. X
  2224. X
  2225. X
  2226. 2) Starting the program
  2227. ~~~~~~~~~~~~~~~~~~~~~~~
  2228. X    When you start SLNR and if the files "AREAS" and "xxx.MSG" are
  2229. X    present in the current directory you will see lines like this :
  2230. X
  2231. Reading Private_mail (12 articles) ..
  2232. Reading biz.sco.general (18 articles) ..
  2233. Reading biz.sco.opendesktop (6 articles) .
  2234. Reading clari.sports.misc (1 articles) .
  2235. Reading comp.bbs.waffle (20 articles) ..
  2236. Reading comp.unix.sysv386 (28 articles) ...
  2237. Reading control (10 articles) .
  2238. Reading news.admin (2 articles) .
  2239. Reading rec.arts.startrek.info (6 articles) .
  2240. Reading rec.humor.funny (24 articles) ...
  2241. Reading rec.humor.oracle (4 articles) .
  2242. Reading uk.misc (190 articles) ...................
  2243. X    
  2244. X    The program prints the list of newsgroups found and for each newsgroup
  2245. X    prints a dot every 10 articles while it is reading them in memory.
  2246. X
  2247. X    Note that in this example the first group is named "Private_mail" which
  2248. X    means that your unread email was selected as well as your newsgroups.
  2249. X
  2250. X
  2251. 2) Reading Usenet Articles
  2252. ~~~~~~~~~~~~~~~~~~~~~~~~~~
  2253. X    When reading usenet articles you will be presented to a page that looks
  2254. X    like that :
  2255. X
  2256. X
  2257. Group uk.misc  <General interest to everyone on UKnet.>          190 articles
  2258. X    From             Lines         Subject
  2259. ============================================================================
  2260. X  1 G.S.Davies          8 Male or female name, help please?                   
  2261.  
  2262. X  2 The Edible Dormo   22 Re: Mail complaint                                  
  2263.  
  2264. X  3 Chris Cooke        19 Re: Queen pays TAX, but there are SOME who don't.   
  2265.  
  2266. X  4 Pete Foulkes       22 Forged 1 pound coins was (Re: 10p coin)             
  2267.  
  2268. X  5 Pete Foulkes       38 Re: Getting robbed at Public Houses                 
  2269.  
  2270. X  6 Graham Toal         9 Re: Male or female name, help please?               
  2271.  
  2272. X  7 Gary Fozzard       13 Bill and Ted's Bogus Journey                        
  2273.  
  2274. X  8 Patrick Gosling    15 Re: Former England Captain                          
  2275.  
  2276. X  9 Mark Turner        15 Re: Moving to UK from US...tips requested           
  2277.  
  2278. X 10 Brian D Milner     10 Broken Cash Register Dump ? ? ? ? ? ? ? ? ? ? ? ?   
  2279.  
  2280. X 11 Ian G Batten        8 Re: Is the police force useful?                     
  2281.  
  2282. X 12 Brian D Milner     34 Dracula (Master, Master, everything is prepared !)  
  2283.  
  2284. X 13 James Petts        22 Re: Is the police force useful?                     
  2285.  
  2286. X 14 Mark Porter         6 UK Inflation figs (6mths) reqd                      
  2287.  
  2288. X 15 Roy Donaldson      25 Re: Car insurance group (again!)                    
  2289.  
  2290. X 16 Tarang K Patel     37 Re: Michael Jackson -- I haven't had a face job!    
  2291.  
  2292. X 17 Tarang K Patel    114 Re: Queen pays TAX, but there are SOME who don't.   
  2293.  
  2294. X 18 Stephen R Cooper  150 Re: Queen pays TAX, but there are SOME who don't.   
  2295.  
  2296. X
  2297. Again View Mail Write next_pg Next_grp Prev_grp Save Hlp Quit 
  2298. X
  2299. X
  2300. X
  2301. X    The first line contains the newsgroup name, it's description (if
  2302. X    available) between angle brackets and the number of article in
  2303. X    that newsgroup. Then the article list itself is divided into 4 columns:
  2304. X
  2305. X    - The first column is the article number, to be referenced when using
  2306. X    the (V)iew (M)ail and (W)rite commands.
  2307. X
  2308. X    - The second column is the author of the article, if the name of the
  2309. X    author cannot be found in the header then the email address is printed.
  2310. X
  2311. X    - The third column is the number of lines in the article. Sometimes big
  2312. X    articles are interesting, but sometimes they are just quotes from
  2313. X    previous articles with "me too" added at the end : this is usenet.
  2314. X
  2315. X    The last line displays the list of available commands (a command not
  2316. X    available does not appear in the list : for example here since we are
  2317. X    at the first page there is no "prev_pg" command).
  2318. X
  2319. X    To call a command just type the first character of the command. (In the
  2320. X    color version, the first letter is of a different color).
  2321. X    Note that some commands are case sensitive ('n' and 'N', 'p' and 'P'
  2322. X    are different).
  2323. X
  2324. X    - Again  :  Used to redisplay the current page again. 
  2325. X
  2326. X    - View   : To view an article. This asks you for the article number and
  2327. X    calls the PAGER. 
  2328. X
  2329. X    - Mail   : To send an electronic mail (either a new mail or an answer
  2330. X    to a message). This will be put in the "mail.rep" file to be uploaded.
  2331. X
  2332. X    - Write  : To post an article (either a new one or a follow-up to a
  2333. X    message). This will be put in the "articles.rep" file to be uploaded.
  2334. X    An article is posted in the current newsgroup. This command is not
  2335. X    available when the group is "Private_mail", your mailbox.
  2336. X
  2337. X    - prev_pg : Previous page of the article list. This command is not
  2338. X    available if you are in the first page of the list. Note that this
  2339. X    command is case sensitive.
  2340. X
  2341. X    - next_pg : Next page of the article list. This command is not
  2342. SHAR_EOF
  2343. true || echo 'restore of slnr/slnr.doc failed'
  2344. fi
  2345. echo 'End of  part 2'
  2346. echo 'File slnr/slnr.doc is continued in part 3'
  2347. echo 3 > _shar_seq_.tmp
  2348. exit 0
  2349.  
  2350. --
  2351. Philippe Goujard <Sysop>                   Email : pgoujard@infocom.co.uk
  2352.   INFOCOM : FREE (yes free!) Usenet access in the UK - (0734) 34 00 55
  2353.  For more information mail "info@infocom.co.uk" a daemon will autoreply
  2354.  
  2355.